/**
* @Author: qinhaoda
* @Description:
* @File: router_discovery
* @Version: 1.0.0
* @Date: 2023/3/1 14:26
 */
package http

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/didi/nightingale/src/models"
	"github.com/didi/nightingale/src/modules/monapi/discovery"
	"github.com/gin-gonic/gin"
	"github.com/toolkits/pkg/errors"
	"github.com/toolkits/pkg/logger"
	"strings"
)

type DiscoveryRecv struct {
	Type string          `json:"type"`
	Data json.RawMessage `json:"data"`
}

func discoveryRulePost(c *gin.Context) {
	var recv []DiscoveryRecv
	errors.Dangerous(c.ShouldBind(&recv))

	buf := &bytes.Buffer{}
	creator := loginUsername(c)
	for _, obj := range recv {
		dis, err := discovery.GetDiscovery(obj.Type)
		errors.Dangerous(err)

		if err := dis.Create([]byte(obj.Data), creator); err != nil {
			if _, ok := err.(discovery.DryRun); ok {
				fmt.Fprintf(buf, "%s\n", err)
			} else {
				errors.Bomb("%s add rule err %s", obj.Type, err)
			}
		}
	}

	buf.WriteString("ok")
	renderData(c, buf.String(), nil)
}

func discoveryRulePut(c *gin.Context) {
	var recv DiscoveryRecv
	errors.Dangerous(c.ShouldBind(&recv))

	dis, err := discovery.GetDiscovery(recv.Type)
	errors.Dangerous(err)

	buf := &bytes.Buffer{}
	creator := loginUsername(c)
	if err := dis.Update([]byte(recv.Data), creator); err != nil {
		if _, ok := err.(discovery.DryRun); ok {
			fmt.Fprintf(buf, "%s\n", err)
		} else {
			errors.Bomb("%s update rule err %s", recv.Type, err)
		}
	}
	buf.WriteString("ok")
	renderData(c, buf.String(), nil)
}

type DiscoveryDelRev struct {
	Type string  `json:"type"`
	Ids  []int64 `json:"ids"`
}

func discoveryRuleDel(c *gin.Context) {
	var recv []DiscoveryDelRev
	errors.Dangerous(c.ShouldBind(&recv))

	username := loginUsername(c)
	for _, obj := range recv {
		for i := 0; i < len(obj.Ids); i++ {
			dis, err := discovery.GetDiscovery(obj.Type)
			errors.Dangerous(err)

			if err := dis.Delete(obj.Ids[i], username); err != nil {
				errors.Dangerous(err)
			}
		}
	}

	renderData(c, "ok", nil)
}

func discoveryRulesGet(c *gin.Context) {
	nid := queryInt64(c, "nid", -1)
	tp := queryStr(c, "type", "stree")
	watch_range := queryStr(c, "watch_range", "current")
	var resp []interface{}

	nids := make([]int64, 0)
	if nid != -1 {
		nids = append(nids, nid)
		switch watch_range {
		case "review":
			node, _ := models.NodeGetById(nid)
			nids = append(nids, nid)
			relatedNodes, _ := node.RelatedNodes()
			for _, relatedNode := range relatedNodes {
				nids = append(nids, relatedNode.Id)
			}
		case "inherit":
			node, _ := models.NodeGetById(nid)
			nodePath := node.Path
			relatedPaths := make([]string, 0)
			fields := strings.Split(nodePath, ".")
			for index := range fields {
				relatedPaths = append(relatedPaths, strings.Join(fields[:index+1], "."))
			}
			relatedNodes, _ := models.NodeByPaths(relatedPaths)
			for _, relatedNode := range relatedNodes {
				nids = append(nids, relatedNode.Id)
			}
		}
	}

	cl, err := discovery.GetDiscovery(tp)
	if err != nil {
		logger.Error(tp, err)
		errors.Dangerous(err)
	}

	ret, err := cl.Gets(nids)
	if err != nil {
		logger.Error(tp, err)
		errors.Dangerous(err)
	}
	resp = append(resp, ret...)

	renderData(c, resp, nil)
}

func discoveryRulesGetUncorrelate(c *gin.Context) {
	nid := queryInt64(c, "nid", -1)
	tp := queryStr(c, "type", "stree")

	var resp []interface{}
	if nid == -1 {
		renderData(c, resp, nil)
		return
	}
	fmt.Printf("nid=%v\n", nid)
	nids := make([]int64, 0)
	node, _ := models.NodeGetById(nid)
	nids = append(nids, nid)
	relatedNodes, _ := node.RelatedNodes()
	for _, relatedNode := range relatedNodes {
		nids = append(nids, relatedNode.Id)
	}
	cl, err := discovery.GetDiscovery(tp)
	if err != nil {
		logger.Error(tp, err)
		errors.Dangerous(err)
	}

	ret, err := cl.GetsUnCorrelate(nids)
	if err != nil {
		logger.Error(tp, err)
		errors.Dangerous(err)
	}
	resp = append(resp, ret...)

	renderData(c, resp, nil)
}

func discoveryRuleGet(c *gin.Context) {
	t := mustQueryStr(c, "type")
	id := mustQueryInt64(c, "id")

	cl, err := discovery.GetDiscovery(t)
	errors.Dangerous(err)

	ret, err := cl.Get(id)
	renderData(c, ret, err)
}
